/*
 * CVisualisator.h
 *
 *  Created on: 04.09.2011
 *      Author: Blinov Kirill
 *      Copyright: LGPL
 */

#ifndef CVISUALISATOR_H_
#define CVISUALISATOR_H_

#include "../TThreadSafeQueue.h"
#include "../Constants.h"
#include "../BasicTypes.h"
#include "CCameraPreprocessor.h"
#include "CRenderer.h"
#include "CFrameBuffer.h"
#include "ShaderTypes.h"
#include "Kernel/CSceneVisualisationProxy.h"
#include <vector>
#include <boost/function.hpp>
#include <stdlib.h>

/*
 *
 */
class CVisualisator
{
private:
	bool                            initialized;
	CCameraPreprocessor*            cameraPreprocessor;
	CRenderer*                      renderer;

	static CVisualisator*           visualisator;

	static const UINT AVERAGE_TEXTURES_IN_SHADER = 3;
private:
	CVisualisator();
	virtual ~CVisualisator();

protected:
	GLuint LoadShader( const std::string FileName, const GLenum ShaderType, std::string** ShaderSource ) const;
	bool CheckShader( const GLuint ShaderName, const char* Source ) const;
	bool CheckProgram(GLuint ProgramName) const;
	std::string* LoadFile( const std::string& Filename ) const;
	std::vector<std::string> FindTexturesInShader( const std::string &ShaderSource );
public:

	bool StartVisualisation( CSceneVisualisationProxy *SceneProxy, TThreadSafeQueue<INPUT_MESSAGE*> *InputMessageQueue );
	void StopVisualisation();
	void ConfigVisualisation( UINT TargetRenderFPS );
	void SetSceneProxy( CSceneVisualisationProxy *SceneProxy );
	void SetDimension( const SCREEN_DIMENSION &ScreenDimension );
	SCREEN_DIMENSION GetDimension() const;
	bool IsInitialized(){ return initialized; };

	GLuint LinkShaderProgram( const GLuint VertexShaderName, const GLuint PixelShaderName ) const;
    bool DefineShaderInputParam( IShaderProgram *Shader, const UINT TextureBlock, const TEXTURE_DESCRIPTOR &Texture )const;
    template <class ConstClass>
    bool DefineShaderInputParam( IShaderProgram *Shader, const std::string Parameter, const ConstClass Value )const;
    template <class FunctionResult>
    bool DefineShaderInputParam( IShaderProgram *Shader, const std::string Parameter, boost::function <FunctionResult()> Value )const;

	GLuint SetUpModels( const std::vector<PURE_COMPRESSED_MODEL*> &ProcessedModels );
	std::pair<GLuint, std::vector<std::string> > SetUpShader( const std::string FileName );
    void DeleteVertexBuffer( const GLuint Name );
    void DeleteVertexBuffer( const std::vector<GLuint> Name );

    static CVisualisator* GetVisualisator();
    static void DeleteVisualisator();
};

template <class ConstClass>
bool
CVisualisator::DefineShaderInputParam( IShaderProgram *Shader, const std::string Parameter, const ConstClass Value )const
{
    GLint Reference = 0;

    if ( SHADER_PARAMETER_TEXTURE_PREFIX[0] == Parameter[0] )
    {
    	Reference = atoi( Parameter.c_str() + 1 );
    }
    else
    {
    	Reference = Shader->GetShaderParamReference( Parameter );
    }

	bool Result = ( Reference >= 0 );

	if ( Result )
	{
		IShaderParamContainer* Container = new CShaderParamConstant<ConstClass>( Reference, Value );
		Shader->AddParamContainer( Container );
	}

	return Result;
}

template <class FunctionResult>
bool
CVisualisator::DefineShaderInputParam( IShaderProgram *Shader, const std::string Parameter,
                                       boost::function <FunctionResult()> Value )const
{
    GLint Reference = Shader->GetShaderParamReference( Parameter );
	bool Result = ( Reference >= 0 );

	if ( Result )
	{
		IShaderParamContainer* Container = new CShaderParamCallback<FunctionResult>( Reference, Value );
		Shader->AddParamContainer( Container );
	}

	return Result;
}


#endif /* CVISUALISATOR_H_ */
